package com.camemax.netty.nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

// NIOBuffer数组的读写操作
// 目标： 实现Gather聚合读以及Scatter分散读
// Channel: 通过ServerSocketChannel监听客户端并开启相应的SocketChannel进行数据交互（即进行缓冲区数组操作）
public class NIOBufferBatch {
    public static void main(String[] args) throws Exception {
        scatteringRead(); // 分散读
        // gatheringWrite(); // 聚合写
    }

    public static SocketChannel socketCreation() throws Exception {
        // 开启ServerSocketChannel通道，监听客户端消息
        ServerSocketChannel channel = ServerSocketChannel.open();
        InetSocketAddress host = new InetSocketAddress("127.0.0.1", 1997);
        SocketChannel socket = channel.bind(host).accept();
        System.out.println("客户端连接成功!");

        return socket;
    }

    public static void scatteringRead() throws Exception {
        SocketChannel socket = socketCreation();
        // 1、创建指定个数的缓冲区数组，并为它们赋值内存大小
        ByteBuffer[] buffers = new ByteBuffer[2];
        // 1.1、分散缓存区数组的内存大小（字节个数）
        buffers[0] = ByteBuffer.allocate(3);
        buffers[1] = ByteBuffer.allocate(6);
        // 读取轮数（可忽略参数）
        int turn = 0;
        // 2、死循环测试缓冲区数组读写功能
        while (true) {
            int readByte = 0; // 记录读取的字节个数
            while (readByte < 9) { // 假定九个字节为一次读取
                turn += 1;
                long read = socket.read(buffers); // 获取该轮次读取的总字节数
                readByte += read; // 结果累加
                // 打印结果（可忽略）
                System.out.println("第一个数组在第" + turn + "次读取了" + readByte + "个字节, 内容为 => " + new String(buffers[0].array(), StandardCharsets.UTF_8));
                System.out.println("第二个数组在第" + turn + "次读取了" + readByte + "个字节, 内容为 => " + new String(buffers[1].array(), StandardCharsets.UTF_8));
            }
            int finalReadByte = readByte;
            Arrays.asList(buffers).forEach(buffer -> {
                System.out.println("position => " + buffer.position()
                        + " limit => " + buffer.limit()
                        + " msgLength => " + finalReadByte);
                buffer.clear(); // position=0归位
            });
        }
    }

    public static void gatheringWrite() throws Exception {
        SocketChannel socket = socketCreation();
        // 1、创建指定个数的缓冲区数组，并为它们赋值内存大小
        ByteBuffer[] buffers = new ByteBuffer[2];
        // 1.1、分散缓存区数组的内存大小（字节个数）
        buffers[0] = ByteBuffer.allocate(3);
        buffers[1] = ByteBuffer.allocate(6);

        // 2、死循环读取数据写入到本地文件
        // 2.1 创建文件输出流，以备聚合写
        String filePath = "D:\\Javas\\netty\\files\\file04.txt";
        File file = new File(filePath);
        FilePathCheck.checkDirectories(file);
        FileChannel channel = new FileOutputStream(file).getChannel();

        // 2.2、 逻辑代码
        while (true) {
            List<ByteBuffer> byteBuffers = Arrays.asList(buffers); // 获取缓冲区数组对象，便于后续操作
            while (true) {
                socket.read(buffers);  // 聚合度
                byteBuffers.forEach(ByteBuffer::flip); // 读写切换
                channel.write(buffers); // 聚合写
                byteBuffers.forEach(buffer -> {
                    System.out.println(new String(buffer.array(), StandardCharsets.UTF_8));
                    System.out.println("position => " + buffer.position() + " limit => " + buffer.limit());
                    buffer.clear(); // 归位 => position=0
                });
            }
        }
    }
}
